module hakem;

import std.range;
import std.conv;
import denetim;

struct TahminSonucu
{
    size_t yeriDeDoğru;    // hem rakamı hem de hanesi doğru olanların adedi
    size_t rakamıDoğru;    // rakamı doğru ama yeri yanlış olanların adedi

    string toString() const
    {
        return (to!string(repeat('+', yeriDeDoğru)) ~
                to!string(repeat('-', rakamıDoğru)));
    }
}

class Hakem
{
    Denetim[] denetimler;

    this(dstring geçerliRakamlar, size_t haneAdedi)
    {
        denetimler = [ new YasalRakamDenetimi(geçerliRakamlar),
                       new RakamTekrarıDenetimi,
                       cast(Denetim)new HaneAdediDenetimi(haneAdedi) ];
    }

    struct Karar
    {
        bool yasal_mı;
        string[] uyarıMesajları;
    }

    Karar yasal_mı(dstring tahmin)
    {
        bool yasal = true;       // baştan yasal olduğunu varsayıyoruz
        string[] uyarıMesajları;

        foreach (denetim; denetimler) {
            if (!denetim.yasal_mı(tahmin)) {
                yasal = false;
                uyarıMesajları ~= denetim.mesaj;
            }
        }

        return Karar(yasal, uyarıMesajları);
    }

    TahminSonucu karşılaştır(dstring tutulan, dstring tahmin)
    in {
        assert(tutulan.length == tahmin.length);

    } out (sonuç) {
        assert((sonuç.yeriDeDoğru + sonuç.rakamıDoğru) <= tutulan.length);

    } body {
        auto sonuç = TahminSonucu(0, 0);

        foreach (i, tutulanRakam; tutulan) {
            foreach (j, tahminRakamı; tahmin) {
                if (tahminRakamı == tutulanRakam) {
                    if (i == j) {
                        ++sonuç.yeriDeDoğru;

                    } else {
                        ++sonuç.rakamıDoğru;
                    }
                }
            }
        }

        return sonuç;
    }
}

unittest
{
    auto hakem = new Hakem("abçdefg", 3);
    Hakem.Karar karar;

    // Başlangıçta yasal olmamalı
    assert(!karar.yasal_mı);

    // Yasal hamle
    karar = hakem.yasal_mı("abç");
    assert(karar.yasal_mı);
    assert(karar.uyarıMesajları.length == 0);

    // Geçersiz rakam
    karar = hakem.yasal_mı("ab3");
    assert(!karar.yasal_mı);
    assert(karar.uyarıMesajları.length == 1);

    // Tekrarlı
    karar = hakem.yasal_mı("aba");
    assert(!karar.yasal_mı);
    assert(karar.uyarıMesajları.length == 1);

    // Yanlış uzunluk
    karar = hakem.yasal_mı("abçd");
    assert(!karar.yasal_mı);
    assert(karar.uyarıMesajları.length == 1);

    // Hepsi yanlış
    karar = hakem.yasal_mı("a7abçd");
    assert(!karar.yasal_mı);
    assert(karar.uyarıMesajları.length == 3);

    TahminSonucu sonuç;

    sonuç = hakem.karşılaştır("bçd", "bçd");
    assert(sonuç == TahminSonucu(3, 0));

    sonuç = hakem.karşılaştır("bçd", "bdç");
    assert(sonuç == TahminSonucu(1, 2));

    sonuç = hakem.karşılaştır("bçd", "dbç");
    assert(sonuç == TahminSonucu(0, 3));
}
